PolymorphismMetadataResolver.java
package org.codefilarete.stalactite.engine.configurer.dslresolver;
import java.util.LinkedHashMap;
import java.util.Map;
import org.codefilarete.stalactite.dsl.PolymorphismPolicy;
import org.codefilarete.stalactite.dsl.PolymorphismPolicy.JoinTablePolymorphism;
import org.codefilarete.stalactite.dsl.PolymorphismPolicy.SingleTablePolymorphism;
import org.codefilarete.stalactite.dsl.PolymorphismPolicy.TablePerClassPolymorphism;
import org.codefilarete.stalactite.dsl.subentity.SubEntityMappingConfiguration;
import org.codefilarete.stalactite.engine.configurer.model.DirectRelationJoin;
import org.codefilarete.stalactite.engine.configurer.model.EntityPolymorphism;
import org.codefilarete.stalactite.engine.configurer.model.Mapping;
import org.codefilarete.stalactite.engine.configurer.dslresolver.InheritanceConfigurationResolver.ResolvedConfiguration;
import org.codefilarete.stalactite.sql.Dialect;
import org.codefilarete.stalactite.sql.ddl.structure.Column;
import org.codefilarete.stalactite.sql.ddl.structure.Table;
import static org.codefilarete.tool.Nullable.nullable;
public class PolymorphismMetadataResolver {
private final Dialect dialect;
public PolymorphismMetadataResolver(Dialect dialect) {
this.dialect = dialect;
}
<C, I> EntityPolymorphism<C, I> resolve(ResolvedConfiguration<C, I> configuration, PolymorphismPolicy<C> polymorphismPolicy) {
// according to polymorphismPolicy type, create the right instances of EntityPolymorphism, fill them with the adhoc values
EntityPolymorphism<C, I> result;
if (polymorphismPolicy instanceof SingleTablePolymorphism) {
result = buildSingleTablePolymorphism(configuration, (SingleTablePolymorphism<C, ?>) polymorphismPolicy);
} else if (polymorphismPolicy instanceof JoinTablePolymorphism) {
result = buildJoinTablePolymorphism(configuration, (JoinTablePolymorphism<C>) polymorphismPolicy);
} else if (polymorphismPolicy instanceof TablePerClassPolymorphism) {
result = buildTablePerClassPolymorphism(configuration, (TablePerClassPolymorphism<C>) polymorphismPolicy);
} else {
throw new UnsupportedOperationException("Unsupported polymorphism policy: " + polymorphismPolicy.getClass());
}
return result;
}
private <C, D extends C, I, DTYPE, T extends Table<T>> org.codefilarete.stalactite.engine.configurer.model.SingleTablePolymorphism<D, I, DTYPE, T>
buildSingleTablePolymorphism(ResolvedConfiguration<C, I> configuration,
SingleTablePolymorphism<C, DTYPE> policy) {
// The discriminator column lives on the entity's own table
String discriminatorColumnName = policy.getDiscriminatorColumn();
Column<T, DTYPE> discriminatorColumn = configuration.getTable().addColumn(discriminatorColumnName, policy.getDiscrimintorType());
org.codefilarete.stalactite.engine.configurer.model.SingleTablePolymorphism<D, I, DTYPE, T> result =
new org.codefilarete.stalactite.engine.configurer.model.SingleTablePolymorphism<>(discriminatorColumn);
PropertyMappingResolver<D, T> propertyMappingResolver = new PropertyMappingResolver<>(dialect.getColumnBinderRegistry());
policy.getSubClasses().forEach(subConfig -> {
SubEntityMappingConfiguration<D> subEntityConfig = (SubEntityMappingConfiguration<D>) subConfig;
Mapping<D, T> mapping = createMapping(configuration, subEntityConfig, (T) configuration.getTable(), propertyMappingResolver);
DTYPE discriminatorValue = policy.getDiscriminatorValue(subConfig.getEntityType());
result.addSubEntity(discriminatorValue, mapping);
});
return result;
}
private <C, D extends C, I, T extends Table<T>, SUBTABLE extends Table<SUBTABLE>> org.codefilarete.stalactite.engine.configurer.model.JoinTablePolymorphism<C, I, T>
buildJoinTablePolymorphism(ResolvedConfiguration<C, I> configuration,
JoinTablePolymorphism<C> policy) {
org.codefilarete.stalactite.engine.configurer.model.JoinTablePolymorphism<C, I, T> result =
new org.codefilarete.stalactite.engine.configurer.model.JoinTablePolymorphism<>();
PropertyMappingResolver<D, T> propertyMappingResolver = new PropertyMappingResolver<>(dialect.getColumnBinderRegistry());
policy.getSubClasses().forEach(subConfig -> {
SubEntityMappingConfiguration<D> subEntityConfig = (SubEntityMappingConfiguration<D>) subConfig;
SUBTABLE subTable = (SUBTABLE) nullable(policy.giveTable(subEntityConfig))
.getOr(() -> new Table<>(configuration.getNamingConfiguration().getTableNamingStrategy().giveName(subEntityConfig.getEntityType())));
// TODO: take into account the overridden columns, or remove this feature in the DSL (we should check that JPA supports it or not)
// SUBTABLE subTable = (SUBTABLE) nullable(tableDefinedByColumnOverride)
// .elseSet(subTable)
// .getOr(() -> new Table<>(configuration.getNamingConfiguration().getTableNamingStrategy().giveName(subEntityConfig.getEntityType())));
// The join is from the sub-entity table FK → parent entity table PK
DirectRelationJoin<T, SUBTABLE, I> join = new DirectRelationJoin<>(
configuration.getTable().getPrimaryKey(),
subTable.<I>getPrimaryKey());
Mapping<D, SUBTABLE> mapping = createMapping(configuration, subEntityConfig, subTable, propertyMappingResolver);
result.addSubEntity(subEntityConfig.getEntityType(), mapping, join);
});
return result;
}
private <C, D extends C, I, T extends Table<T>, SUBTABLE extends Table<SUBTABLE>> org.codefilarete.stalactite.engine.configurer.model.TablePerClassPolymorphism<C, I>
buildTablePerClassPolymorphism(ResolvedConfiguration<C, I> configuration,
TablePerClassPolymorphism<C> policy) {
Map<Class<? extends C>, Mapping<? extends C, ?>> subEntities = new LinkedHashMap<>();
PropertyMappingResolver<D, T> propertyMappingResolver = new PropertyMappingResolver<>(dialect.getColumnBinderRegistry());
policy.getSubClasses().forEach(subConfig -> {
SubEntityMappingConfiguration<D> subEntityConfig = (SubEntityMappingConfiguration<D>) subConfig;
SUBTABLE subTable = (SUBTABLE) nullable(policy.giveTable(subEntityConfig))
.getOr(() -> new Table<>(configuration.getNamingConfiguration().getTableNamingStrategy().giveName(subEntityConfig.getEntityType())));
Mapping<D, SUBTABLE> mapping = createMapping(configuration, subEntityConfig, subTable, propertyMappingResolver);
subEntities.put(subConfig.getEntityType(), mapping);
});
return new org.codefilarete.stalactite.engine.configurer.model.TablePerClassPolymorphism<>(subEntities);
}
private <C, D extends C, I, T extends Table<T>, SUBTABLE extends Table<SUBTABLE>> Mapping<D, SUBTABLE> createMapping(ResolvedConfiguration<C, I> configuration,
SubEntityMappingConfiguration<D> subEntityConfig,
SUBTABLE subTable,
PropertyMappingResolver<D, T> propertyMappingResolver) {
Mapping<D, SUBTABLE> mapping = new Mapping<>(subEntityConfig.getEntityType(), subTable);
mapping.getPropertyMappingHolder().addMapping(propertyMappingResolver.resolve(subEntityConfig.getPropertiesMapping(), (T) configuration.getTable(), configuration.getNamingConfiguration().getColumnNamingStrategy()));
return mapping;
}
}